package com.netintech.common.utils.hikSdk;

import ClientDemo.HCNetSDK;
import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import lombok.extern.slf4j.Slf4j;

import java.util.*;

/**
 * 海康sdk操作工具类
 *
 * @author luda
 */
@Slf4j
public class HikSdkUtil {
    public static HCNetSDK hCNetSDK = HCNetSDK.INSTANCE;


    /**
     * 初始化sdk
     *
     * @return
     */
    public static boolean initSdk() {
        return hCNetSDK.NET_DVR_Init();
    }


    /**
     * 用户注册设备
     *
     * @param deviceIp
     * @param port
     * @param userName
     * @param password
     * @return -1表示失败，其他值表示返回的用户ID值。
     */
    public static LoginResult login(String deviceIp, int port, String userName, String password) {
        LoginResult loginResult = new LoginResult();
        HCNetSDK.NET_DVR_DEVICEINFO_V30 lpDeviceInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V30();
        NativeLong lUserID = hCNetSDK.NET_DVR_Login_V30(deviceIp,
                (short) port, userName, password, lpDeviceInfo);
//        -1表示失败，其他值表示返回的用户ID值
        if (!Objects.equals(new NativeLong(-1L), lUserID)) {
            loginResult.setSuccess(true);
            loginResult.setLUserID(lUserID);
            loginResult.setM_strDeviceInfo(lpDeviceInfo);
        } else {
            log.error("注册失败错误码：" + hCNetSDK.NET_DVR_GetLastError());
        }
        return loginResult;
    }


    /**
     * 注销设备
     *
     * @param lUserID 用户ID号，NET_DVR_Login_V40等登录接口的返回值
     * @return
     */
    public static boolean logout(NativeLong lUserID) {
        return hCNetSDK.NET_DVR_Logout_V30(lUserID);
    }

    /**
     * 释放SDK资源
     *
     * @return
     */
    public static boolean cleanUp() {
        return hCNetSDK.NET_DVR_Cleanup();
    }

    /**
     * 根据文件类型、时间查找设备录像文件
     *
     * @param lUserID     用户ID号，NET_DVR_Login_V40等登录接口的返回值
     * @param startYear
     * @param startMouth
     * @param startDay
     * @param startHour
     * @param startMinute
     * @param startSecond
     * @param stopYear
     * @param stopMouth
     * @param stopDay
     * @param stopHour
     * @param stopMinute
     * @param stopSecond
     * @param channelNum
     * @param useCard     是否带卡号查找 0：否；1：是
     * @return -1表示失败，其他值作为NET_DVR_FindClose等函数的参数。接口返回失败请调用NET_DVR_GetLastError获取错误码，通过错误码判断出错原因
     */
    public static List<FindFileResult> findFile(NativeLong lUserID
            , Integer startYear, Integer startMouth, Integer startDay, Integer startHour, Integer startMinute, Integer startSecond
            , Integer stopYear, Integer stopMouth, Integer stopDay, Integer stopHour, Integer stopMinute, Integer stopSecond
            , long channelNum, int useCard
    ) {
        List<FindFileResult> findFileResults = new ArrayList<>();

        HCNetSDK.NET_DVR_FILECOND m_strFilecond = genFilecond(startYear, startMouth, startDay, startHour, startMinute, startSecond, stopYear, stopMouth, stopDay, stopHour, stopMinute, stopSecond, channelNum, useCard);

        HCNetSDK.NET_DVR_FINDDATA_V30 strFile = new HCNetSDK.NET_DVR_FINDDATA_V30();
        NativeLong lFindFile = hCNetSDK.NET_DVR_FindFile_V30(lUserID, m_strFilecond);
//        -1表示失败，其他值作为NET_DVR_FindClose等函数的参数
        long findFile = lFindFile.longValue();
        if (findFile > -1) {
            log.info("查询到文件--" + findFile);
        } else {
            return findFileResults;
        }
        NativeLong lnext;
        strFile = new HCNetSDK.NET_DVR_FINDDATA_V30();
        while (true) {
            lnext = hCNetSDK.NET_DVR_FindNextFile_V30(lFindFile, strFile);
            //搜索成功
            if (lnext.longValue() == HCNetSDK.NET_DVR_FILE_SUCCESS) {
                findFileResults.add(FindFileResult.builder()
                        .startTime(strFile.struStartTime.toStringTime())
                        .endTime(strFile.struStopTime.toStringTime())
                        .build());
            } else {
                if (lnext.longValue() == HCNetSDK.NET_DVR_ISFINDING) {//搜索中
                    log.info("搜索中");
                } else {
                    if (lnext.longValue() == HCNetSDK.NET_DVR_FILE_NOFIND) {
                        log.info("没有搜到文件");
                        return findFileResults;
                    } else {
                        log.info("搜索文件结束");
                        boolean flag = hCNetSDK.NET_DVR_FindClose_V30(lFindFile);
                        if (!flag) {
                            log.info("结束搜索失败");
                        }
                        return findFileResults;
                    }
                }
            }
        }

    }

    /**
     * 生成 欲查找的文件信息结构
     *
     * @param startYear
     * @param startMouth
     * @param startDay
     * @param startHour
     * @param startMinute
     * @param startSecond
     * @param stopYear
     * @param stopMouth
     * @param stopDay
     * @param stopHour
     * @param stopMinute
     * @param stopSecond
     * @param channelNum
     * @param useCard
     * @return
     */
    private static HCNetSDK.NET_DVR_FILECOND genFilecond(Integer startYear, Integer startMouth, Integer startDay, Integer startHour, Integer startMinute, Integer startSecond, Integer stopYear, Integer stopMouth, Integer stopDay, Integer stopHour, Integer stopMinute, Integer stopSecond, long channelNum, int useCard) {
        HCNetSDK.NET_DVR_FILECOND m_strFilecond = new HCNetSDK.NET_DVR_FILECOND();
        m_strFilecond.struStartTime = new HCNetSDK.NET_DVR_TIME();
        m_strFilecond.struStopTime = new HCNetSDK.NET_DVR_TIME();
        m_strFilecond.struStartTime.dwYear = startYear;
        m_strFilecond.struStartTime.dwMonth = startMouth;
        m_strFilecond.struStartTime.dwDay = startDay;
        m_strFilecond.struStartTime.dwHour = startHour;
        m_strFilecond.struStartTime.dwMinute = startMinute;
        m_strFilecond.struStartTime.dwSecond = startSecond;
        m_strFilecond.struStopTime.dwYear = stopYear;
        m_strFilecond.struStopTime.dwMonth = stopMouth;
        m_strFilecond.struStopTime.dwDay = stopDay;
        m_strFilecond.struStopTime.dwHour = stopHour;
        m_strFilecond.struStopTime.dwMinute = stopMinute;
        m_strFilecond.struStopTime.dwSecond = stopSecond;

        m_strFilecond.lChannel = new NativeLong(channelNum);//通道号
//        文件类型：定时录像
        m_strFilecond.dwFileType = 0;
//        是否锁定：0-未锁定文件，1-锁定文件，0xff表示所有文件（包括锁定和未锁定）
        m_strFilecond.dwIsLocked = 0xff;
        m_strFilecond.dwUseCardNo = useCard;  //是否使用卡号
        return m_strFilecond;
    }

    /**
     * 根据nvr获取相机数字通道号
     *
     * @param lUserID
     * @param m_strDeviceInfo 注册后的设备信息
     * @return 相机数字通道号
     */
    public static List<Integer> getCamChannelNumsByNvr(NativeLong lUserID, HCNetSDK.NET_DVR_DEVICEINFO_V30 m_strDeviceInfo) {
        List<Integer> result = new ArrayList<>();
        int startChannelNum = 32;
        IntByReference ibrBytesReturned = new IntByReference(0);//获取IP接入配置参数
        boolean bRet = false;

        HCNetSDK.NET_DVR_IPPARACFG m_strIpparaCfg = new HCNetSDK.NET_DVR_IPPARACFG();
        m_strIpparaCfg.write();
        Pointer lpIpParaConfig = m_strIpparaCfg.getPointer();
        bRet = hCNetSDK.NET_DVR_GetDVRConfig(lUserID, HCNetSDK.NET_DVR_GET_IPPARACFG, new NativeLong(0)
                , lpIpParaConfig, m_strIpparaCfg.size(), ibrBytesReturned);
        m_strIpparaCfg.read();
//        TRUE表示成功，FALSE表示失败
        if (bRet) {
            //设备支持IP通道
            for (int iChannum = 0; iChannum < HCNetSDK.MAX_IP_CHANNEL; iChannum++) {
                if (m_strIpparaCfg.struIPChanInfo[iChannum].byEnable == 1) {
                    result.add(iChannum + m_strDeviceInfo.byStartChan + startChannelNum);
                }
            }
        }
        return result;
    }


}
